home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Graphics 3D / SetupGL / SetupDSp.c < prev    next >
Encoding:
Text File  |  2000-09-28  |  25.6 KB  |  830 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        SetupDSp.c
  3.  
  4.     Contains:    Functions to enable building and destorying a DSp fullscreen context
  5.  
  6.     Written by:    Geoff Stahl (ggs)
  7.  
  8.     Copyright:    Copyright © 1999 Apple Computer, Inc., All Rights Reserved
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <7>     3/21/00    ggs     Added windowed mode and clean up various implementation details
  13.          <6>     2/22/00    ggs     fix fades
  14.          <5>     1/26/00    ggs     Add fade code back in, ensure NULL pointer/context checks are in
  15.          <4>     1/24/00    ggs     add new disclaimer, protection from NULL dispose, better
  16.                                     software renderer handling
  17.          <3>    12/18/99    ggs     Fixed err use before init
  18.          <2>    12/18/99    ggs     Fix headers
  19.          <1>    11/28/99    ggs     Initial add.  Split of just DSp handling functions.  Added total
  20.                                     device RAM checks, better step downs using actual supported
  21.                                     resolutions. Need to add user verify for contexts that require
  22.                                     it, integration of this in context step down, and a freq bit
  23.                                     field.
  24.          <1>    11/11/99    ggs     Initial Add
  25.  
  26.     Disclaimer:    You may incorporate this sample code into your applications without
  27.                 restriction, though the sample code has been provided "AS IS" and the
  28.                 responsibility for its operation is 100% yours.  However, what you are
  29.                 not permitted to do is to redistribute the source as "DSC Sample Code"
  30.                 after having made changes. If you're going to re-distribute the source,
  31.                 we require that you make it clear in the source that the code was
  32.                 descended from Apple Sample Code, but that you've made changes.
  33. */
  34.  
  35.  
  36. // Usage notes: 
  37. // kUseFades enables gamma fades for activates and deactivates
  38. #define kUseFades
  39.  
  40. //kUseRAMCheck enables estimated video card RAM checks
  41. #define kUseRAMCheck
  42.  
  43.  
  44. // system includes ----------------------------------------------------------
  45.  
  46. #include <fp.h>
  47.  
  48. #include <string.h>
  49.  
  50.  
  51. // project includes ---------------------------------------------------------
  52.  
  53. #include "Error Handler.h"
  54. #include "SetupDSp.h"
  55.  
  56. // globals (internal/private) -----------------------------------------------
  57.  
  58. enum 
  59.     kMaxNumRes = 64, // max number of resolution slots
  60.     kMaxRefreshFreq = 75 
  61. }; 
  62.  
  63. Boolean gDSpStarted = false;
  64. Boolean gNeedFade = false;
  65.  
  66. // prototypes (internal/private) --------------------------------------------
  67.  
  68. DSpContextReference * ReserveUnusedDevices (GDHandle hGD);
  69. OSStatus FreeUnusedDevices (GDHandle hGD, DSpContextReference ** ppContextRefUnused);
  70. void BuildResolutionList (GDHandle hGD, Point * pResList, UInt32 * pFreqList);
  71. OSStatus DoDeviceRAMCheck (pstructGLInfo pcontextInfo, Point * pResList, UInt32 * pFreqList, GLint depthSizeSupport);
  72. Boolean DoContextStepDown (pstructGLInfo pcontextInfo, DSpContextAttributes * pContextAttributes, Point * pResList, UInt32 * pFreqList);
  73.  
  74.  
  75. // functions (internal/private) ---------------------------------------------
  76.  
  77. // ReserveUnusedDevices
  78.  
  79. // reserves contexts on unused devices to vprevent their selection by DSp, returns list of these devices
  80.  
  81. DSpContextReference * ReserveUnusedDevices (GDHandle hGD)
  82. {
  83.     DSpContextAttributes theContextAttributes;
  84.     DSpContextReference * pContextRefUnused = NULL;
  85.     GDHandle hDevice = DMGetFirstScreenDevice (true); // check number of screens
  86.     OSStatus err = noErr;
  87.     DisplayIDType displayID = 0;
  88.     short numDevices = 0, indexDevice = 0;
  89.     
  90.     do
  91.     {
  92.         numDevices++;
  93.         hDevice = DMGetNextScreenDevice (hDevice, true);
  94.     }
  95.     while (hDevice);
  96.     numDevices--; // only count unused screens
  97.     if (numDevices)
  98.     {
  99.         pContextRefUnused = (DSpContextReference *) NewPtr ((long) sizeof (DSpContextReference) * numDevices);
  100.         hDevice = DMGetFirstScreenDevice (true); // check number of screens
  101.         do
  102.         {
  103.             if (hDevice != hGD)    // if this device is not the one the user chose
  104.             {
  105.                 if (noErr == DSpReportError (DMGetDisplayIDByGDevice (hDevice, &displayID, false)))
  106.                     if (noErr == DSpReportError (DSpGetFirstContext (displayID, &pContextRefUnused [indexDevice]))) // get a context and
  107.                         if (noErr == DSpReportError (DSpContext_GetAttributes (pContextRefUnused [indexDevice], &theContextAttributes))) // find attributes
  108.                             DSpReportError (DSpContext_Reserve (pContextRefUnused [indexDevice], &theContextAttributes)); // reserve it
  109.                 indexDevice++;
  110.             }
  111.             hDevice = DMGetNextScreenDevice (hDevice, true);
  112.         }
  113.         while (hDevice);
  114.     }
  115.     return pContextRefUnused;
  116. }
  117.  
  118. // --------------------------------------------------------------------------
  119.  
  120. // FreeUnusedDevices
  121.  
  122. // frees screen that were previously reserved to prevent selection
  123.  
  124. OSStatus FreeUnusedDevices (GDHandle hGD, DSpContextReference ** ppContextRefUnused)
  125. {
  126.     OSStatus err = noErr;
  127.     GDHandle hDevice = DMGetFirstScreenDevice (true); // check number of screens
  128.     short indexDevice = 0;
  129.  
  130.     do
  131.     {
  132.         if (hDevice != hGD)    // if this device is not the one the user chose
  133.         {
  134.             err = DSpContext_Release (*ppContextRefUnused [indexDevice]); // release it
  135.             DSpReportError (err);
  136.             indexDevice++;
  137.         }
  138.         hDevice = DMGetNextScreenDevice (hDevice, true);
  139.     }
  140.     while (hDevice);
  141.     
  142.     if (*ppContextRefUnused)
  143.         DisposePtr ((Ptr) *ppContextRefUnused);
  144.     *ppContextRefUnused = NULL;
  145.     return err;
  146. }
  147.  
  148. // --------------------------------------------------------------------------
  149.  
  150. // BuildResolutionList
  151.  
  152. // builds a list of supported resolutions and frequencies for GDevice
  153.  
  154. void BuildResolutionList (GDHandle hGD, Point * pResList, UInt32 * pFreqList)
  155. {
  156.     DSpContextAttributes theContextAttributes;
  157.     DSpContextReference currContext;
  158.     OSStatus err;
  159.     DisplayIDType displayID = 0;
  160.     short i;
  161.     
  162.     for (i = 0; i < kMaxNumRes; i++)    // clear resolution list
  163.     {
  164.         pResList [i].h = 0x7FFF;
  165.         pResList [i].v = 0x7FFF;
  166.         pFreqList [i] = 0;            // some context require certain frequencies find highest for each (not higher than 85
  167.     }
  168.  
  169.     err = DMGetDisplayIDByGDevice (hGD, &displayID, true);
  170.     if (noErr != err)
  171.         ReportErrorNum ("DMGetDisplayIDByGDevice error", err);
  172.     else
  173.     {
  174.         if (noErr == DSpReportError (DSpGetFirstContext (displayID, &currContext)))
  175.             do
  176.             {    
  177.                 // insertion sort into resolution list
  178.                 if (noErr == DSpReportError (DSpContext_GetAttributes (currContext, &theContextAttributes)))
  179.                 {
  180.                     Point pntTemp;
  181.                     Boolean fDone = false;
  182.                     short i = 0;
  183.                     while ((i < kMaxNumRes) && (!fDone))
  184.                     {
  185.                         if ((theContextAttributes.displayWidth == pResList [i].h) && (theContextAttributes.displayHeight == pResList [i].v)) //skip
  186.                         {
  187.                             if ((pFreqList [i] == 0) || ((theContextAttributes.frequency <= (kMaxRefreshFreq << 16)) && (theContextAttributes.frequency > pFreqList [i])))
  188.                                 pFreqList [i] = theContextAttributes.frequency;
  189.                             break;
  190.                         }
  191.                         if (theContextAttributes.displayWidth * theContextAttributes.displayHeight < pResList [i].h * pResList [i].v) //insert
  192.                         {
  193.                             pntTemp = pResList [i];
  194.                             pResList [i].h = theContextAttributes.displayWidth;
  195.                             pResList [i].v = theContextAttributes.displayHeight;
  196.                             pFreqList [i] = theContextAttributes.frequency;
  197.                             fDone = true;
  198.                         }
  199.                         i++;
  200.                     }
  201.                     // i points to next element to switch; finish array swaps (if 
  202.                     while ((i < kMaxNumRes) && (fDone))
  203.                     {
  204.                         Point pntSwitch = pResList [i];
  205.                         pResList [i++] = pntTemp;
  206.                         pntTemp = pntSwitch;
  207.                     }
  208.                 }
  209.                 err = DSpGetNextContext (currContext, &currContext);
  210.                 if (noErr != err)
  211.                 {
  212.                     if (kDSpContextNotFoundErr != err) 
  213.                         DSpReportError (err);
  214.                     currContext = 0;    // ensure we drop out
  215.                 }
  216.             } 
  217.             while (currContext);
  218.         else
  219.             ReportErrorNum ("DSpGetFirstContext error", err);
  220.     }    
  221.     // zeroize unused elements
  222.     for (i = 0; i < kMaxNumRes; i++)
  223.         if ((pResList [i].h == 0x7FFF) || (pResList [i].v == 0x7FFF))
  224.         {
  225.             pResList [i].h = 0;
  226.             pResList [i].v = 0;
  227.         }
  228. }
  229.  
  230. // --------------------------------------------------------------------------
  231.  
  232. // DoDeviceRAMCheck
  233.  
  234. // checks requested allocation against device RAM
  235. // Note: may modify pcontextInfo
  236. // this should be equal or less strigent than OpenGL actual allocation to avoid failing on valid drawables
  237.  
  238. OSStatus DoDeviceRAMCheck (pstructGLInfo pcontextInfo, Point * pResList, UInt32 * pFreqList, GLint depthSizeSupport)
  239. {
  240.     float frontBufferFactor = 1.0, backBufferFactor = 0.0; // amount of screen(front) or request(back) sized buffers required, in bytes
  241.     Point pntFrontBuffer; // size of front buffer that wil be allocated
  242.     short i, indexFrontBuffer; 
  243.     OSStatus err = noErr;
  244.  
  245.     // must take into account the entire front buffer, so figure out what screen resolution we are really going to use
  246.     // find front buffer for request
  247.     i = 0;
  248.     while (((pResList [i].h < pcontextInfo->width) || (pResList [i].v < pcontextInfo->height)) &&
  249.            ((pResList [i].h != 0) || (pResList [i].v != 0)) &&
  250.            (i < kMaxNumRes))
  251.         i++;
  252.     // save front buffer sizes
  253.     pntFrontBuffer.h = pResList [i].h;
  254.     pntFrontBuffer.v = pResList [i].v;
  255.     // if we have a valid frequnecy for the context set it (to ensure a good selection
  256.     pcontextInfo->freq = pFreqList [i] >> 16;
  257.     indexFrontBuffer = i;
  258.     
  259.     // front buffers required
  260.     if (16 == pcontextInfo->pixelDepth)
  261.         frontBufferFactor *= 2.0;
  262.     else if (32 == pcontextInfo->pixelDepth)
  263.         frontBufferFactor *= 4.0;
  264.         
  265.     // back buffers required    
  266.     backBufferFactor = 0.0;
  267.     i = 0;
  268.     while (64 > i)
  269.         if (AGL_DOUBLEBUFFER == pcontextInfo->aglAttributes[i++])
  270.         {
  271.             if (16 == pcontextInfo->pixelDepth)
  272.                 backBufferFactor = 2.0;
  273.             else if (32 == pcontextInfo->pixelDepth)
  274.                 backBufferFactor = 4.0;
  275.             break;
  276.         }
  277.     i = 0;
  278.     while (64 > i)
  279.         if (AGL_DEPTH_SIZE == pcontextInfo->aglAttributes[i++])
  280.         {
  281.             short requestDepth = pcontextInfo->aglAttributes[i];
  282.             GLint bit = 0x00000001;
  283.             short currDepth = 0, prevDepth = 0;
  284. //            if (depthSizeSupport)
  285. //            {
  286.             do
  287.             {
  288.                 if (bit & depthSizeSupport)    // if the card supports the depth
  289.                 {
  290.                     prevDepth = currDepth;
  291.                     switch (bit)
  292.                     {
  293.                         case AGL_1_BIT:
  294.                             currDepth = 1;
  295.                             break;
  296.                         case AGL_2_BIT:
  297.                             currDepth = 2;
  298.                             break;
  299.                         case AGL_3_BIT:
  300.                             currDepth = 3;
  301.                             break;
  302.                         case AGL_4_BIT:
  303.                             currDepth = 4;
  304.                             break;
  305.                         case AGL_5_BIT:
  306.                             currDepth = 5;
  307.                             break;
  308.                         case AGL_6_BIT:
  309.                             currDepth = 6;
  310.                             break;
  311.                         case AGL_8_BIT:
  312.                             currDepth = 8;
  313.                             break;
  314.                         case AGL_10_BIT:
  315.                             currDepth = 10;
  316.                             break;
  317.                         case AGL_12_BIT:
  318.                             currDepth = 12;
  319.                             break;
  320.                         case AGL_16_BIT:
  321.                             currDepth = 16;
  322.                             break;
  323.                         case AGL_24_BIT:
  324.                             currDepth = 24;
  325.                             break;
  326.                         case AGL_32_BIT:
  327.                             currDepth = 32;
  328.                             break;
  329.                         case AGL_48_BIT:
  330.                             currDepth = 48;
  331.                             break;
  332.                         case AGL_64_BIT:
  333.                             currDepth = 64;
  334.                             break;
  335.                         case AGL_96_BIT:
  336.                             currDepth = 96;
  337.                             break;
  338.                         case AGL_128_BIT:
  339.                             currDepth = 128;
  340.                             break;
  341.                     }
  342.                 }
  343.                 bit *= 2;
  344.             } while (!((requestDepth > prevDepth) && (requestDepth <= currDepth)) && (bit < AGL_128_BIT + 1));
  345. //            }
  346. //            else // no card depth support info
  347. //                currDepth = requestDepth;  // we don't have card info thus assume we can support exact depth requested (may fail later but will always be equal or less stringent)
  348.             if ((AGL_128_BIT >= bit) && (0 != currDepth))
  349.                 backBufferFactor += (float) currDepth / 8.0;
  350.             break;
  351.         }
  352.         
  353.     // What we now have:
  354.     //  pcontextInfo->width, height: request width and height
  355.     //  pResList: sorted list of resolutions supported on this display
  356.     //  pntFrontBuffer : size of front buffer that will currently be allocated
  357.     //  indexFrontBuffer: position in array of current front buffer request
  358.     //  frontBufferFactor: number of screen resolution size buffers that will be needed
  359.     //  backBufferFactor: number of request size buffers that will be needed
  360.     
  361.     // if we see zero VRAM here we must be looking at the software renderer thus this check is moot.
  362.     if (pcontextInfo->VRAM == 0)
  363.     {
  364.         // no changes required
  365.         return noErr;
  366.     }
  367.     
  368.     
  369.     // find a context size that can support our texture requirements in the current total VRAM
  370.     if ((pcontextInfo->VRAM - pcontextInfo->textureRAM) < (pntFrontBuffer.h * pntFrontBuffer.v * frontBufferFactor + 
  371.                                                            pcontextInfo->width * pcontextInfo->height * backBufferFactor))
  372.     {
  373.         if (pcontextInfo->fDepthMust && pcontextInfo->fSizeMust)
  374.         {
  375.             // cannot accomdate request
  376.             ReportError ("Not enough total VRAM for drawable and textures (depth buffer and pixel size must be as requested)");
  377.             return err;
  378.         }
  379.         else if (pcontextInfo->fSizeMust) // if we can adjust the size, try adjusting the 
  380.         {
  381.             // try 16 bit if must size is true
  382.             if ((pcontextInfo->pixelDepth > 16) &&
  383.                 (pcontextInfo->VRAM - pcontextInfo->textureRAM) > (pntFrontBuffer.h * pntFrontBuffer.v * frontBufferFactor / 2.0 + 
  384.                                                                       pcontextInfo->width * pcontextInfo->height * (backBufferFactor - 2.0)))
  385.                 pcontextInfo->pixelDepth = 16;
  386.             else
  387.             {
  388.                 // cannot accomdate request
  389.                 ReportError ("Not enough total VRAM for drawable and textures");
  390.                 return err;
  391.             }
  392.         }
  393.         else // can adjust size and might be able to adjust depth
  394.         {    // make drawable fit
  395.             Boolean fFound = false;
  396.             // see if we can just adjust the pixel depth
  397.             if ((pcontextInfo->pixelDepth > 16) &&    // if we are requesting 32 bit
  398.                 (!pcontextInfo->fDepthMust) &&         // if we can adjust the pixel depth
  399.                 (pcontextInfo->VRAM - pcontextInfo->textureRAM) > (pntFrontBuffer.h * pntFrontBuffer.v * frontBufferFactor / 2.0 + 
  400.                                                                       pcontextInfo->width * pcontextInfo->height * (backBufferFactor - 2.0)))
  401.             {
  402.                 fFound = true;
  403.                 pcontextInfo->pixelDepth = 16;
  404.             }
  405.             else // pixel depth alone wont do it
  406.             {
  407.                 i = indexFrontBuffer - 1;
  408.                 while (i >= 0)
  409.                 {
  410.                     //
  411.                     if ((pcontextInfo->VRAM - pcontextInfo->textureRAM) > (pResList [i].h * pResList [i].v * frontBufferFactor + 
  412.                                                                               pResList [i].h * pResList [i].v * backBufferFactor))
  413.                     {
  414.                         fFound = true;
  415.                         pcontextInfo->width = pResList [i].h;
  416.                         pcontextInfo->height = pResList [i].v;
  417.                         pcontextInfo->freq = pFreqList [i] >> 16;
  418.                         break;
  419.                     }
  420.                     else if ((pcontextInfo->pixelDepth > 16) &&    // if we are requesting 32 bit
  421.                              (!pcontextInfo->fDepthMust) &&     // if we can adjust the pixel depth
  422.                              (pcontextInfo->VRAM - pcontextInfo->textureRAM) > (pResList [i].h * pResList [i].v * frontBufferFactor / 2.0 + 
  423.                                                                                 pResList [i].h * pResList [i].v * (backBufferFactor - 2.0)))
  424.                     {
  425.                         fFound = true;
  426.                         pcontextInfo->width = pResList [i].h;
  427.                         pcontextInfo->height = pResList [i].v;
  428.                         pcontextInfo->freq = pFreqList [i] >> 16;
  429.                         pcontextInfo->pixelDepth = 16;
  430.                         break;
  431.                     }
  432.                     i--;
  433.                 }
  434.                 // we tried the smallest screen size and still need to use less VRAM, adjust backbuffer to what is available
  435.                 if ((!fFound) && (((pcontextInfo->VRAM - pcontextInfo->textureRAM) - pResList [0].h * pResList [0].v * frontBufferFactor) > 0))
  436.                 {
  437.                     float factor;
  438.                     fFound = true;
  439.                     factor = sqrt((float) (pcontextInfo->width * pcontextInfo->height * backBufferFactor) / 
  440.                                   (float) ((pcontextInfo->VRAM - pcontextInfo->textureRAM) - pResList [0].h * pResList [0].v * frontBufferFactor));
  441.                     pcontextInfo->width /= factor;
  442.                     pcontextInfo->height /= factor;
  443.                     pcontextInfo->freq = pFreqList [0] >> 16;
  444.                 }
  445.             }
  446.             if (!fFound)
  447.             {
  448.                 // cannot accomdate request
  449.                 ReportError ("Not enough total VRAM for drawable and textures");
  450.                 return err;
  451.             }
  452.  
  453.         }
  454.     }
  455.     return noErr;
  456. }
  457.  
  458. // --------------------------------------------------------------------------
  459.  
  460. // DoContextStepDown
  461.  
  462. // steps down through frequencies, depths and sizes to try to find a valid context
  463. // bounded by flags for SizeMust and DepthMust
  464. // Note: may modify pcontextInfo
  465.  
  466. Boolean DoContextStepDown (pstructGLInfo pcontextInfo, DSpContextAttributes * pContextAttributes, Point * pResList, UInt32 * pFreqList)
  467. {
  468.     // find current resolution
  469.     short i = 0; 
  470.     while (((pResList [i].h <= pContextAttributes->displayWidth) || (pResList [i].v <= pContextAttributes->displayHeight)) && 
  471.             ((pResList [i].h != 0) || (pResList [i].v != 0)) &&
  472.             (i < kMaxNumRes))
  473.         i++;
  474.     i--; // i points to index of current resolution
  475.     
  476.     if (pcontextInfo->fSizeMust) // adjust depth only
  477.     {
  478.         if (pcontextInfo->pixelDepth > 16)    // also try pixel depth step down
  479.         {
  480.             pContextAttributes->displayBestDepth = 16;
  481.             pContextAttributes->backBufferBestDepth = 16;
  482.         }
  483.         else
  484.             return false; // no more options to try
  485.     }
  486.     else if (pcontextInfo->fDepthMust) // adjust size only
  487.     {
  488.         if (i > 0)
  489.         {
  490.             i--; // i was pointing at current resolution, now it is pointing at new resolution to try
  491.             // set new resolution
  492.             pContextAttributes->displayWidth = pResList [i].h;
  493.             pContextAttributes->displayHeight = pResList [i].v;
  494.             pcontextInfo->freq = pFreqList [i] >> 16;
  495.         }
  496.         else
  497.             return false;
  498.     }
  499.     else // adjust size and depth
  500.     {
  501.         if (pContextAttributes->displayBestDepth > 16)
  502.         {
  503.             pContextAttributes->displayBestDepth = 16;
  504.             pContextAttributes->backBufferBestDepth = 16;
  505.         }
  506.         else if (i > 0)
  507.         {
  508.             i--; // i was pointing at current resolution, now it is pointing at new resolution to try
  509.             // reset pixel depth
  510.             pContextAttributes->displayBestDepth = pcontextInfo->pixelDepth;
  511.             pContextAttributes->backBufferBestDepth = pcontextInfo->pixelDepth;
  512.             // set new resolution
  513.             pContextAttributes->displayWidth = pResList [i].h;
  514.             pContextAttributes->displayHeight = pResList [i].v;
  515.             pcontextInfo->freq = pFreqList [i] >> 16;
  516.         }
  517.         else
  518.             return false;
  519.             
  520.     }
  521.     return true;
  522. }
  523.  
  524. #pragma mark -
  525. // functions (public) -------------------------------------------------------
  526.  
  527. // StartDSp
  528.  
  529. // handles starting up DrawSprocket
  530.  
  531. OSStatus StartDSp (void)
  532. {
  533.     OSStatus err = noErr;
  534.     
  535.     if (!gDSpStarted)
  536.     {
  537.         // check for DSp
  538.         if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpStartup) 
  539.         {
  540.             ReportError ("DSp not installed");
  541.             return noErr;
  542.         }    
  543.  
  544.         err = DSpReportError (DSpStartup()); // start DSp
  545.         if (noErr != err)
  546.             return err;
  547.         else
  548.             gDSpStarted = true;
  549.     }
  550.     return err;        
  551. }
  552.  
  553. // --------------------------------------------------------------------------
  554.  
  555. // ShutdownDSpContext
  556.  
  557. // shuts down DrawSprocket
  558.  
  559. void ShutdownDSp (void)
  560. {
  561.     if (gDSpStarted)
  562.     {
  563.         DSpShutdown ();
  564.         gDSpStarted = false;
  565.     }
  566. }
  567.  
  568. #pragma mark -
  569. // --------------------------------------------------------------------------
  570.  
  571. // BuildDSpContext
  572.  
  573. // contexInfo and tries to allocate the corresponding DSp context
  574.  
  575. // Inputs:     hGD: GDHandle to device to look at
  576. //            pcontextInfo: request and requirements for cotext and drawable
  577.  
  578. // Outputs: *pdspContext as allocated
  579. //            pcontextInfo:  allocated parameters
  580.  
  581. // if fail to allocate: pdspContext will be NULL
  582. // if error: will return error pdspContext will be NULL
  583.  
  584. OSStatus BuildDSpContext (DSpContextReference* pdspContext, GDHandle hGD, GLint depthSizeSupport, pstructGLInfo pcontextInfo)
  585. {
  586.     DSpContextAttributes theContextAttributes, foundAttributes;
  587.     DSpContextReference * pContextRefUnused;
  588.     UInt32 aFreqList [kMaxNumRes];
  589.     Point aResList [kMaxNumRes]; // list for resolution information
  590.     OSStatus err = noErr;
  591.     
  592.     *pdspContext = 0;
  593.  
  594.     if (!gDSpStarted)
  595.     {
  596.         // check for DSp
  597.         if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpStartup) 
  598.         {
  599.             ReportError ("DSp not installed");
  600.             return noErr;
  601.         }    
  602.  
  603.         err = DSpReportError (DSpStartup()); // start DSp
  604.         if (noErr != err)
  605.         {
  606.             return err;
  607.         }
  608.         else
  609.             gDSpStarted = true;
  610.     }        
  611.  
  612.     // reserve contexts on other screens to prevent their selection
  613.     pContextRefUnused = ReserveUnusedDevices (hGD);
  614.     
  615.     // build resolution list
  616.     BuildResolutionList (hGD, aResList, aFreqList);
  617.     
  618.     // handle default pixel depths
  619.     if (pcontextInfo->pixelDepth == 0)    // default
  620.     {
  621.         pcontextInfo->pixelDepth = (**(**hGD).gdPMap).pixelSize;
  622.         if (pcontextInfo->pixelDepth < 16)
  623.             pcontextInfo->pixelDepth = 16;
  624.     }
  625.  
  626. #ifdef kUseRAMCheck
  627.     if (noErr != DoDeviceRAMCheck (pcontextInfo, aResList, aFreqList, depthSizeSupport))
  628.         return err;
  629. #endif // kUseRAMCheck
  630.  
  631.     // Note: DSp < 1.7.3 REQUIRES the back buffer attributes even if only one buffer is required
  632.     memset(&theContextAttributes, 0, sizeof (DSpContextAttributes));
  633.     theContextAttributes.displayWidth                = pcontextInfo->width;
  634.     theContextAttributes.displayHeight                = pcontextInfo->height;
  635.     theContextAttributes.displayBestDepth            = pcontextInfo->pixelDepth;
  636.     theContextAttributes.backBufferBestDepth        = pcontextInfo->pixelDepth;
  637.     do
  638.     {    
  639.         theContextAttributes.frequency                = pcontextInfo->freq * 0x10000;
  640.         theContextAttributes.colorNeeds                = kDSpColorNeeds_Require;
  641.         theContextAttributes.displayDepthMask        = kDSpDepthMask_All;
  642.         theContextAttributes.backBufferDepthMask    = kDSpDepthMask_All;
  643.         theContextAttributes.pageCount                = 1; // only the front buffer is needed
  644.         err = DSpFindBestContext(&theContextAttributes, pdspContext);
  645.         if (noErr != err)    // if we had any errors, reset for next try
  646.             if (!DoContextStepDown (pcontextInfo, &theContextAttributes, aResList, aFreqList))
  647.                 break; // have run out of options
  648.     } while (err == kDSpContextNotFoundErr);
  649.  
  650.     // check find best context errors
  651.     if (kDSpContextNotFoundErr == err)
  652.     {    
  653.         *pdspContext = 0;
  654.         return noErr;
  655.     }
  656.     else if (noErr != err)
  657.     {
  658.         DSpReportError (err);
  659.         *pdspContext = 0;
  660.         return err;
  661.     }
  662.     
  663.     err = DSpReportError (DSpContext_GetAttributes (*pdspContext, &foundAttributes));
  664.     if (noErr != err)
  665.     {
  666.         *pdspContext = 0;
  667.         return err;
  668.     }
  669.     // reset width and height to full screen and handle our own centering
  670.     // HWA will not correctly center less than full screen size contexts
  671.     theContextAttributes.displayWidth         = foundAttributes.displayWidth;
  672.     theContextAttributes.displayHeight         = foundAttributes.displayHeight;
  673.     theContextAttributes.pageCount            = 1; // only the front buffer is needed
  674.     theContextAttributes.contextOptions        = 0 | kDSpContextOption_DontSyncVBL; // no page flipping and no VBL sync needed
  675.  
  676.     err = DSpReportError (DSpContext_Reserve(*pdspContext, &theContextAttributes )); // reserve our context
  677.     if (noErr != err)
  678.     {
  679.         *pdspContext = 0;
  680.         return err;
  681.     }
  682.     if (gNeedFade == true)
  683.     {
  684.         DSpReportError (DSpContext_CustomFadeGammaOut (NULL, NULL, fadeTicks));
  685.         gNeedFade = false;
  686.     }
  687.     err = DSpReportError (DSpContext_SetState (*pdspContext, kDSpContextState_Active)); // activate our context
  688.     if (noErr != err)
  689.     {
  690.         DSpContext_Release (*pdspContext);
  691.         DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks));
  692.         *pdspContext = 0;
  693.         return err;
  694.     }
  695.  
  696.     FreeUnusedDevices (hGD, &pContextRefUnused);
  697.     
  698.     if (!pcontextInfo->fSizeMust)    // if we got whatever was available
  699.     {
  700.         // reset inputs to what was allocated (constrain aspect ratio)
  701.         // unless we ask for smaller, then leave the same
  702.         if ((pcontextInfo->width > foundAttributes.displayWidth) || (pcontextInfo->height > foundAttributes.displayHeight))
  703.         {
  704.             float hFactor = (float) pcontextInfo->width / (float) foundAttributes.displayWidth;
  705.             float vFactor = (float) pcontextInfo->height / (float) foundAttributes.displayHeight;
  706.             if (hFactor > vFactor)
  707.             {
  708.                 pcontextInfo->width = foundAttributes.displayWidth;
  709.                 pcontextInfo->height /= hFactor;    
  710.             }
  711.             else
  712.             {
  713.                 pcontextInfo->height = foundAttributes.displayHeight;
  714.                 pcontextInfo->width /= vFactor;    
  715.             }
  716.         }
  717.     }
  718.     // else still use inputs to allocate drawable
  719.     
  720.     pcontextInfo->freq = foundAttributes.frequency / 0x10000;
  721.     pcontextInfo->pixelDepth = foundAttributes.displayBestDepth;
  722.  
  723.     return noErr;
  724. }
  725.  
  726. //-----------------------------------------------------------------------------------------------------------------------
  727.  
  728. // Deactivates and dumps context
  729.  
  730. void DestroyDSpContext (DSpContextReference* pdspContext)
  731. {
  732.     if (gDSpStarted)
  733.     {
  734.         if (*pdspContext)
  735.         {
  736.             DSpContext_SetState(*pdspContext, kDSpContextState_Inactive );
  737.             DSpReportError (DSpContext_CustomFadeGammaIn (NULL, NULL, fadeTicks));
  738.             DSpContext_Release (*pdspContext);
  739.             *pdspContext = NULL;
  740.         }
  741.     }
  742. }
  743.  
  744.  
  745. #pragma mark -
  746. //-----------------------------------------------------------------------------------------------------------------------
  747.  
  748. OSStatus DSpContext_CustomFadeGammaIn (DSpContextReference inContext, const RGBColor *fadeColor,  long fadeTicks) 
  749. {
  750.     OSStatus err = noErr;
  751. #ifndef kUseFades
  752.     #pragma unused (inContext, fadeColor, fadeTicks)
  753. #else
  754.     RGBColor inZeroIntensityColor;
  755.     long currTick;
  756.     UInt16 step = 800 / fadeTicks;
  757.     short x, percent = 0;
  758.  
  759.     if (gDSpStarted)
  760.     {
  761.         if (fadeTicks == 0)
  762.             fadeTicks = 1;
  763.         if (fadeColor == NULL) 
  764.         {
  765.             inZeroIntensityColor.red = 0x0000;
  766.             inZeroIntensityColor.green = 0x0000;
  767.             inZeroIntensityColor.blue = 0x0000;
  768.         }
  769.         else 
  770.             inZeroIntensityColor = *fadeColor;
  771.         currTick = TickCount ();
  772.         for (x = 1; x <= fadeTicks; x++) 
  773.         {
  774.             percent =  step * x >> 3;
  775.             err = DSpContext_FadeGamma(inContext, percent, &inZeroIntensityColor);
  776.             if (err != noErr) 
  777.                 break;
  778.             while (currTick >= TickCount ()) 
  779.                 SystemTask ();
  780.             currTick = TickCount ();
  781.         }
  782.         if (err == noErr)
  783.             err = DSpContext_FadeGamma(inContext, 100, &inZeroIntensityColor);
  784.     }
  785. #endif // kUseFades
  786.     return err;
  787. }
  788.  
  789. //-----------------------------------------------------------------------------------------------------------------------
  790.  
  791. OSStatus DSpContext_CustomFadeGammaOut (DSpContextReference inContext, const RGBColor *fadeColor, long fadeTicks ) 
  792. {
  793.     
  794.     OSStatus err = noErr;
  795. #ifndef kUseFades
  796.     #pragma unused (inContext, fadeColor, fadeTicks)
  797. #else
  798.     RGBColor inZeroIntensityColor;
  799.     long currTick;
  800.     UInt16 step = 800 / fadeTicks;
  801.     short x, percent = 0;
  802.  
  803.     if (gDSpStarted)
  804.     {
  805.         if (fadeTicks == 0)
  806.             fadeTicks = 1;                                // ensure we do not have zero fade time
  807.         if (fadeColor == NULL) 
  808.         {
  809.             inZeroIntensityColor.red = 0x0000;
  810.             inZeroIntensityColor.green = 0x0000;
  811.             inZeroIntensityColor.blue = 0x0000;
  812.         }
  813.         else 
  814.             inZeroIntensityColor = *fadeColor;
  815.         currTick = TickCount ();
  816.         for (x = fadeTicks - 1; x >= 0; x--) 
  817.         {
  818.             percent =  step * x >> 3;
  819.             err = DSpContext_FadeGamma(inContext, percent, &inZeroIntensityColor);
  820.             if (err != noErr) 
  821.                 break;
  822.             while (currTick >= TickCount ()) 
  823.                 SystemTask ();
  824.             currTick = TickCount ();
  825.         }
  826.     }
  827. #endif // kUseFades
  828.     return err;
  829. }